package model;

import java.util.ArrayList;
import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.TimeStep;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.controllers.BuoyancyController;
import org.jbox2d.dynamics.controllers.BuoyancyControllerDef;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import controller.Global;

public class Stage {
	private int worldTileWidth = 100;
	public boolean paused, scrollBackground;
	public static int TOP = 0, SIDE = 1;
	private Image background;
	private Vec2 p1, p2;
	private float ppos, pdir, parallaxWidth;
	private Contacts contactListener;
	public BuoyancyControllerDef testDef;
	public static BuoyancyController buoyancy;
	public boolean stopBuoyancy = false;
	public ArrayList<Entity> objectList;

	public Stage(int view, Image background, boolean scrollBackground) {
		Entity entity;

		// initialize world variables
		AABB aabb = new AABB(new Vec2(-Global.worldSize, -Global.worldSize),
				new Vec2(Global.worldSize, Global.worldSize));
		Global.world = new World(aabb, new Vec2(0, -10f), true);

		paused = false;
		objectList = new ArrayList<Entity>();
		Global.stage = this;
		Global.hud = new HUD();

		// create test water
		testDef = new BuoyancyControllerDef();
		testDef.angularDrag = 2f;
		testDef.density = 5f;
		testDef.linearDrag = 5f;
		testDef.normal = new Vec2(0, 1f);
		testDef.offset = Global.waterLevel;
		buoyancy = (BuoyancyController) Global.world.createController(testDef);
		Global.water = new Water();

		// setup contact listener
		contactListener = new Contacts();
		Global.world.setContactListener(contactListener);

		// setup background parallax
		this.background = background;
		p1 = new Vec2(0, 0);
		p2 = new Vec2(0, 0);
		pdir = ppos = 0;
		if (background != null) {
			parallaxWidth = (float) background.getWidth()
					* ((float) Global.screenY / (float) background.getHeight());
		}
		this.scrollBackground = scrollBackground;

		// create side view world
		if (view == SIDE) {

			// create floor
			for (int i = 0; i < worldTileWidth; i++) {
				entity = Assets.getInstance().getEntity(
						"assets/entities/rock.txt");
				entity.x = (float) i - (worldTileWidth / 2);
				entity.y = 0f;
				Factory.createEntity(entity);
			}
		}

		// create top view world
		else if (view == TOP) {
			Global.world.setGravity(new Vec2(0, 0));
		}

		// create player
		entity = Assets.getInstance().getEntity("assets/entities/girl.txt");
		entity.x = 0;
		entity.y = Global.waterLevel + 3.5f;
		entity.name = "player";
		Global.player = Factory.createEntity(entity);

		// create player platform over water
		entity = Assets.getInstance().getEntity("assets/entities/block.txt");
		entity.x = 0;
		entity.y = Global.waterLevel + 2;
		Factory.createEntity(entity);
		entity = Assets.getInstance().getEntity("assets/entities/block.txt");
		entity.x = 1;
		entity.y = Global.waterLevel + 2;
		Factory.createEntity(entity);
		entity = Assets.getInstance().getEntity("assets/entities/block.txt");
		entity.x = -1;
		entity.y = Global.waterLevel + 2;
		Factory.createEntity(entity);

		// play music
		// Assets.getInstance().getMusic("assets/music/music.ogg").loop();
	}

	public void pause() {
		Body b = Global.world.getBodyList();
		paused = true;

		while (b != null) {
			b.putToSleep();
			b = b.getNext();
		}
	}

	public void unpause() {
		Body b = Global.world.getBodyList();
		paused = false;

		while (b != null) {
			b.wakeUp();
			b = b.getNext();
		}
	}

	public void update() {
		Body body = Global.world.getBodyList();
		Entity data;

		if (!paused) {

			p1.x = Global.player.getPosition().x;
			p1.y = Global.player.getPosition().y;

			// update physics world state
			Global.world.step(Global.physicsStep, 1);

			// update buoyancy calculations
			TimeStep t = new TimeStep();
			t.dtRatio = Global.physicsStep;
			buoyancy.step(t);
			Global.water.update();

			// update all object states
			while (body != null) {
				data = ((Entity) body.getUserData());
				if (data != null) {
					data.update();
				}
				body = body.getNext();
			}

			p2.x = Global.player.getPosition().x;
			p2.y = Global.player.getPosition().y;
		}
	}

	private void renderBackground() {

		if (background != null) {

			if (!scrollBackground) {
				background.draw(0, 0, Global.screenX, Global.screenY);
			} else {
				pdir = (p1.x - p2.x) * 10.0f;
				ppos = ppos + pdir;

				if ((ppos + parallaxWidth) < 0) {
					ppos = parallaxWidth;
				} else if (ppos > parallaxWidth) {
					ppos = 0;
				}
				background.draw(ppos, 0, parallaxWidth, Global.screenY);

				if (ppos < (Global.screenX - parallaxWidth)) {
					background.draw(ppos + parallaxWidth, 0, parallaxWidth,
							Global.screenY);
				}
				if (ppos < Global.screenX - (Global.screenX - parallaxWidth)) {
					background.draw(ppos - parallaxWidth, 0, parallaxWidth,
							Global.screenY);
				}
				if (ppos < -parallaxWidth + (Global.screenX - parallaxWidth)) {
					background.draw(ppos + parallaxWidth + parallaxWidth, 0,
							parallaxWidth, Global.screenY);
				}
			}
		}
	}

	public void render(Graphics g) {
		Entity data;
		Body b = Global.world.getBodyList();

		renderBackground();

		Global.water.render(g, Assets.getInstance().getImage(
				"assets/gfx/underwater2.png"));

		objectList = new ArrayList<Entity>();

		while (b != null) {
			data = (Entity) b.getUserData();

			if (data != null) {
				data.x = b.getPosition().x;
				data.y = b.getPosition().y;
				if (!data.isSensor) {
					objectList.add(data);
				} else {
					data.render();
				}
			}
			b = b.getNext();
		}

		// draw objects after sensors
		for (Entity e : objectList) {
			e.render();
		}

		// draw water
		Global.water.render(g, Assets.getInstance().getImage(
				"assets/gfx/cyan50.png"));
	}
}
